<?php
namespace ShadowVc;

use ShadowVc\Utils\LtLogger;

/**
 * sdk客户端
 *
 * @author chenxiaochun
 *
 */
class EopClient {
  public $appKey;

  public $secret;

  public $serverUrl = "http://api.shadowvc.com/rest";

  public $format = "json";

  public $connectTimeout;

  public $readTimeout;

  /** 是否打开入参check**/
  public $checkRequest = true;

  protected $signMethod = "md5";

  protected $apiVersion = "2.0";

  protected $sdkVersion = "eop-sdk-php-20140525";

  private $curlch;

  private $curlNum = 0;

  public function __construct($appKey, $secret) {
    $this->appKey = $appKey;
    $this->secret = $secret;
  }

  protected function generateSign($params) {
    ksort($params);

    $stringToBeSigned = $this->secret;
    foreach ($params as $k => $v) {
      if ("@" != mb_substr($v, 0, 1)) {
        $stringToBeSigned .= "$k$v";
      }
    }
    unset($k, $v);
    $stringToBeSigned .= $this->secret;

    return strtoupper(md5($stringToBeSigned));
  }

  public function curl($url, $postFields = null) {
    if ($this->curlNum == 0) {
      $this->curlch = curl_init();
    }

    $this->curlNum++;
    curl_setopt($this->curlch, CURLOPT_URL, $url);
    curl_setopt($this->curlch, CURLOPT_FAILONERROR, false);
    curl_setopt($this->curlch, CURLOPT_RETURNTRANSFER, true);
    if ($this->readTimeout) {
      curl_setopt($this->curlch, CURLOPT_TIMEOUT, $this->readTimeout);
    }
    if ($this->connectTimeout) {
      curl_setopt($this->curlch, CURLOPT_CONNECTTIMEOUT, $this->connectTimeout);
    }
    //https 请求
    if (strlen($url) > 5 && strtolower(substr($url, 0, 5)) == "https") {
      curl_setopt($this->curlch, CURLOPT_SSL_VERIFYPEER, false);
      curl_setopt($this->curlch, CURLOPT_SSL_VERIFYHOST, false);
    }

    if (is_array($postFields) && 0 < count($postFields)) {
      $postBodyString = "";
      $postMultipart = false;
      foreach ($postFields as $k => $v) {
        if ("@" != substr($v, 0, 1))//判断是不是文件上传
        {
          $postBodyString .= "$k=" . urlencode($v) . "&";
        } else//文件上传用multipart/form-data，否则用www-form-urlencoded
        {
          $postMultipart = true;
        }
      }
      unset($k, $v);
      curl_setopt($this->curlch, CURLOPT_POST, true);
      if ($postMultipart) {
        curl_setopt($this->curlch, CURLOPT_POSTFIELDS, $postFields);
      } else {
        curl_setopt($this->curlch, CURLOPT_POSTFIELDS, substr($postBodyString, 0, -1));
      }
    }
    $reponse = curl_exec($this->curlch);

    if (curl_errno($this->curlch)) {
      throw new \Exception(curl_error($this->curlch), 0);
    } else {
      $httpStatusCode = curl_getinfo($this->curlch, CURLINFO_HTTP_CODE);
      if (200 !== $httpStatusCode) {
        throw new \Exception($reponse, $httpStatusCode);
      }
    }

    return $reponse;
  }

  protected function logCommunicationError($apiName, $requestUrl, $errorCode, $responseTxt) {
    $localIp = isset($_SERVER["SERVER_ADDR"]) ? $_SERVER["SERVER_ADDR"] : "CLI";
//    $logger = new LtLogger;
//    $logger->conf["log_file"] = rtrim('\\/') . '/' . "logs/top_comm_err_" . $this->appKey . "_" . date("Y-m-d") . ".log";
//    $logger->conf["separator"] = "^_^";
//    $logData = array(
//      date("Y-m-d H:i:s"),
//      $apiName,
//      $this->appKey,
//      $localIp,
//      PHP_OS,
//      $this->sdkVersion,
//      $requestUrl,
//      $errorCode,
//      str_replace("\n", "", $responseTxt)
//    );
//    $logger->log($logData);

  }

  public function execute($request, $accessKey = null) {
    if ($this->checkRequest) {
      try {
        $request->check();
      } catch (\Exception $e) {
        $result = new \stdClass();
        $result->code = $e->getCode();
        $result->msg = $e->getMessage();
        return $result;
      }
    }
    //组装系统参数
    $sysParams["appKey"] = $this->appKey;
    $sysParams["v"] = $this->apiVersion;
    $sysParams["format"] = $this->format;
    $sysParams["signMethod"] = $this->signMethod;
    $sysParams["method"] = $request->getApiMethodName();
    $sysParams["timestamp"] = date("Y-m-d H:i:s");

    $sysParams["sdkVersion"] = $this->sdkVersion;
    if (null != $accessKey) {
      $sysParams["accessKey"] = $accessKey;
    }

    //获取业务参数
    $apiParams = $request->getApiParas();

    //签名
    $sysParams["sign"] = $this->generateSign(array_merge($apiParams, $sysParams));

    //系统参数放入GET请求串
    $requestUrl = $this->serverUrl . "?";
    foreach ($sysParams as $sysParamKey => $sysParamValue) {
      $requestUrl .= "$sysParamKey=" . urlencode($sysParamValue) . "&";
    }
    $requestUrl = substr($requestUrl, 0, -1);

    //发起HTTP请求
    try {
      $resp = $this->curl($requestUrl, $apiParams);
    } catch (\Exception $e) {
      $this->logCommunicationError($sysParams["method"], $requestUrl, "HTTP_ERROR_" . $e->getCode(), $e->getMessage());
      $result = new \stdClass();
      $result->code = $e->getCode();
      $result->msg = $e->getMessage();
      return $result;
    }

    //解析EOP返回结果 返回结果只有json
    $respObject = json_decode($resp, true);
    if (null !== $respObject) {
      $respWellFormed = true;
      foreach ($respObject as $propKey => $propValue) {
        $respObject = $propValue;
      }
    }
    if (!empty($respObject['subCode'])) {
      throw new \Exception($respObject['subMsg']);
    }

    return $respObject;
  }

  public function __destruct() {
    // TODO: Implement __destruct() method.
    if ($this->curlNum > 0) {
      curl_close($this->curlch);
    }
  }
}